package ccm.communicate.tcp;

import ccm.common.CCMConfigManager;
import ccm.common.ReceiveDataEvent;
import ccm.common.StatusChangeEvent;
import ccm.communicate.common.Communicate;
import ccm.communicate.common.NotStartException;
import ccm.communicate.common.SendFailedException;

import javax.swing.*;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TcpServer extends Communicate
{
    static
    {
        CCMConfigManager.setIntegerIfAbsent("ccm/communicate/tcp/TcpServer/port",1217);
    }

    ;
    final protected Receiver[] receivers=new Receiver[2];
    /**
     * 保存端口号
     */
    protected int port=CCMConfigManager.getInteger("ccm/communicate/tcp/TcpServer/port");
    /**
     * 保存链接
     */
    protected ServerSocket serverSocket;

    public TcpServer()
    {
        super();
        for(int i=0;i<receivers.length;++i)
        {
            Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate((receivers[i]=new Receiver()),0,500,TimeUnit.MILLISECONDS);
        }
    }

    public int getPort()
    {
        return port;
    }

    public void setPort(int port)
    {
        boolean is=isOpen();
        if(is){stop();}
        this.port=port;
        if(is){start();}
        CCMConfigManager.setInteger("ccm/communicate/tcp/TcpServer/port",this.port);
    }

    /**
     * 启动
     */
    public void start()
    {
        try
        {
            serverSocket=new ServerSocket(port);
            callStatusChangeListener(StatusChangeEvent.START);
        }catch(IOException e)
        {
            serverSocket=null;
            e.printStackTrace();
            JOptionPane.showMessageDialog(null,e.getMessage(),"错误",JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * 停止
     */
    public void stop()
    {
        try
        {
            if(serverSocket!=null){serverSocket.close();}
        }catch(IOException ex)
        {
            ex.printStackTrace();
        }
        serverSocket=null;
        callStatusChangeListener(StatusChangeEvent.STOP);
    }

    /**
     * 检查是否开启
     *
     * @return true表示开启
     * false表示关闭
     */
    public boolean isOpen()
    {
        return (serverSocket!=null&&!serverSocket.isClosed());
    }

    /**
     * 获取配置用的面板
     *
     * @return 配置用的面板
     */
    public JPanel getConfigJPanel()
    {
        return new TcpServerConfigJPanel(this);
    }

    @Override
    synchronized public void receiveData(ReceiveDataEvent event) throws NotStartException, SendFailedException
    {
        if(!isOpen()){throw new NotStartException();}
        try
        {
            for(Receiver receiver: receivers)
            {
                receiver.send(event.getData());
            }
        }catch(IOException e)
        {
            e.printStackTrace();
            throw new SendFailedException();
        }
    }

    private class Receiver extends Thread
    {
        private int index=1;
        private Socket client;

        public Receiver()
        {
            super();
            Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(()->
            {
                if(serverSocket!=null)
                {
                    if(client!=null&&!client.isClosed())
                    {
                        index++;
                        if(index>=2&&(index%10)==0){System.out.println("prepare to close "+index);}
                        if(index>=10000)
                        {
                            try
                            {
                                client.close();
                            }catch(IOException ignore)
                            {
                            }
                        }
                    }
                }
                else{close();}
            },0,100,TimeUnit.MILLISECONDS);
        }

        public void close()
        {
            try
            {
                if(client!=null)
                {
                    client.close();
                    client=null;
                }
            }catch(IOException e)
            {
                e.printStackTrace();
            }
        }

        public void run()
        {
            if(serverSocket!=null)
            {
                try
                {
                    client=serverSocket.accept();
                    System.out.println("与客户端"+client.getInetAddress()+"连接成功！");
                    for(Receiver receiver: receivers)
                    {
                        if(!receiver.equals(this)){receiver.close();}
                    }
                    callStatusChangeListener(StatusChangeEvent.START);
                    InputStream inputStream=client.getInputStream();
                    index=0;
                    while(serverSocket!=null&&client!=null&&!client.isClosed())
                    {
                        byte[] buffer=new byte[10240];
                        int len;
                        if((len=inputStream.read(buffer))!=-1)
                        {
                            byte[] buf=new byte[len];
                            System.arraycopy(buffer,0,buf,0,len);
                            callReceiveDataListener(new ReceiveDataEvent(TcpServer.this,buf));
                            index=0;
                        }
                    }
                }catch(Exception e)
                {
                    e.printStackTrace();
                }
                System.out.println("与客户端连接断开！");
                close();
            }
            else{close();}
        }

        public void send(byte[] data) throws IOException
        {
            if(client!=null){client.getOutputStream().write(data);}
        }
    }
}
